package com.chaoxing.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.chaoxing.config.ChaoXingConfig;
import com.chaoxing.entity.*;
import com.chaoxing.utils.EncryptUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ChaoXingService {
    private static final String LOGIN_URL = "https://passport2.chaoxing.com/fanyalogin";
    private static final String COURSE_LIST_URL = "https://mooc1-1.chaoxing.com/visit/courselistdata";
    private static final String ACTIVE_LIST_URL = "https://mobilelearn.chaoxing.com/v2/apis/active/student/activelist";
    private static final String PPT_ACTIVE_INFO_URL = "https://mobilelearn.chaoxing.com/v2/apis/active/getPPTActiveInfo";
    private static final String PRESIGN_URL = "https://mobilelearn.chaoxing.com/newsign/preSign";
    private static final String PPT_SIGN_URL = "https://mobilelearn.chaoxing.com/pptSign/stuSignajax";
    private static final String CHAT_GROUP_LIST_URL = "https://im.chaoxing.com/webim/me";
    private static final String CHAT_GROUP_PRESIGN_URL = "https://mobilelearn.chaoxing.com/sign/preStuSign";
    private static final String CHAT_GROUP_SIGN_URL = "https://mobilelearn.chaoxing.com/sign/stuSignajax";
    private static final String MOBILE_ACTIVITY_LIST = "https://mobilelearn.chaoxing.com/ppt/activeAPI/taskactivelist";
    
    @Autowired
    private ChaoXingConfig config;
    
    private OkHttpClient client;
    private User currentUser;
    private final Map<String, List<Cookie>> cookieStore = new HashMap<>();
    
    @PostConstruct
    public void init() {
        this.client = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .cookieJar(new CookieJar() {
                    @Override
                    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                        cookieStore.put(url.host(), cookies);
                    }
                    
                    @Override
                    public List<Cookie> loadForRequest(HttpUrl url) {
                        List<Cookie> cookies = cookieStore.get(url.host());
                        return cookies != null ? cookies : new ArrayList<>();
                    }
                })
                .build();
        
        currentUser = new User();
    }
    
    public boolean login() {
        try {
            String encodedPassword = EncryptUtil.encryptPassword(config.getPassword());
            
            FormBody formBody = new FormBody.Builder()
                    .add("uname", config.getUsername())
                    .add("password", encodedPassword)
                    .add("fid", "-1")
                    .add("t", "true")
                    .add("refer", "https%253A%252F%252Fi.chaoxing.com")
                    .add("forbidotherlogin", "0")
                    .add("validate", "")
                    .build();
            
            Request request = new Request.Builder()
                    .url(LOGIN_URL)
                    .post(formBody)
                    .addHeader("Content-Type", "application/x-www-form-urlencoded")
                    .addHeader("X-Requested-With", "XMLHttpRequest")
                    .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
                    .build();
            
            try (Response response = client.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    log.error("登录失败: HTTP {}", response.code());
                    return false;
                }
                
                String body = response.body().string();
                JSONObject json = JSON.parseObject(body);
                
                if (json.getBoolean("status")) {
                    currentUser.setUid(json.getString("uid"));
                    currentUser.setName(json.getString("name"));
                    currentUser.setUsername(config.getUsername());
                    currentUser.setLoginStatus(true);
                    
                    // 保存cookies
                    List<String> cookieHeaders = response.headers("Set-Cookie");
                    String cookieString = cookieHeaders.stream()
                            .map(cookie -> cookie.split(";")[0])
                            .collect(Collectors.joining("; "));
                    currentUser.setCookies(cookieString);
                    
                    log.info("用户 {} 登录成功", currentUser.getName());
                    return true;
                } else {
                    log.error("登录失败: {}", json.getString("msg2"));
                    return false;
                }
            }
        } catch (Exception e) {
            log.error("登录异常", e);
            return false;
        }
    }
    
    public List<Course> getCourses() {
        List<Course> courses = new ArrayList<>();
        
        try {
            FormBody formBody = new FormBody.Builder()
                    .add("courseType", "1")
                    .add("courseFolderId", "0")
                    .add("courseFolderSize", "0")
                    .build();
            
            Request request = new Request.Builder()
                    .url(COURSE_LIST_URL)
                    .post(formBody)
                    .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                    .addHeader("Accept", "text/html, */*; q=0.01")
                    .addHeader("Cookie", currentUser.getCookies())
                    .build();
            
            try (Response response = client.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    log.error("获取课程列表失败: HTTP {}", response.code());
                    return courses;
                }
                
                Document doc = Jsoup.parse(response.body().string());
                doc.select(".course").forEach(element -> {
                    Course course = new Course();
                    String courseLink = element.select("a").attr("href");
                    
                    // 解析courseId和clazzId
                    String[] params = courseLink.split("[?&]");
                    for (String param : params) {
                        if (param.startsWith("courseid=")) {
                            course.setCourseId(param.substring(9));
                        } else if (param.startsWith("clazzid=")) {
                            course.setClazzId(param.substring(8));
                        }
                    }
                    
                    course.setCourseName(element.select(".course-name").text());
                    course.setTeacherName(element.select(".teacher").text());
                    courses.add(course);
                });
            }
        } catch (Exception e) {
            log.error("获取课程列表异常", e);
        }
        
        return courses;
    }
    
    public List<Activity> getActivities(Course course) {
        List<Activity> activities = new ArrayList<>();
        
        try {
            String url = String.format("%s?fid=0&courseId=%s&classId=%s&_=%s", 
                    ACTIVE_LIST_URL, course.getCourseId(), course.getClazzId(), System.currentTimeMillis());
            
            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("Cookie", currentUser.getCookies())
                    .build();
            
            try (Response response = client.newCall(request).execute()) {
                if (!response.isSuccessful()) {
                    log.error("获取活动列表失败: HTTP {}", response.code());
                    return activities;
                }
                
                String body = response.body().string();
                JSONObject jsonData = JSON.parseObject(body);
                
                if (jsonData.getJSONObject("data") != null) {
                    log.debug("课程 {} 的活动数据: {}", course.getCourseName(), body);
                    JSONArray activeList = jsonData.getJSONObject("data").getJSONArray("activeList");
                    
                    if (activeList != null && activeList.size() > 0) {
                        log.debug("课程 {} 有 {} 个活动", course.getCourseName(), activeList.size());
                        for (int i = 0; i < activeList.size(); i++) {
                        JSONObject activityJson = activeList.getJSONObject(i);
                        Integer otherId = activityJson.getInteger("otherId");
                        Integer status = activityJson.getInteger("status");
                        
                        // 跳过没有otherId或status的活动
                        if (otherId == null || status == null) {
                            log.debug("活动缺少otherId或status字段，跳过");
                            continue;
                        }
                        
                        // 判断是否是有效签到活动（otherId 0-5，status为1进行中 或 status为2已结束但时间在2小时内）
                        if (otherId >= 0 && otherId <= 5) {
                            // 活动开始时间
                            long startTime = activityJson.getLong("startTime");
                            long currentTime = System.currentTimeMillis();
                            long timeDiff = (currentTime - startTime) / 1000; // 秒
                            
                            // status=1表示进行中，status=2表示已结束
                            if (status == 1) {
                                log.info("发现进行中的签到活动: {} (otherId={}, status={}, 已开始{}秒)", 
                                    activityJson.getString("nameOne"), otherId, status, timeDiff);
                            } else if (status == 2 && timeDiff < 300) { // 已结束但在5分钟内
                                log.info("发现刚结束的签到活动（可能错过）: {} (otherId={}, status={}, 已结束{}秒)", 
                                    activityJson.getString("nameOne"), otherId, status, timeDiff);
                                continue; // 跳过已结束的
                            } else {
                                log.debug("活动不是有效的签到活动: otherId={}, status={}, name={}, 时间差={}秒", 
                                    otherId, status, activityJson.getString("nameOne"), timeDiff);
                                continue;
                            }
                            
                            // 只处理进行中且在2小时内的签到
                            if (status == 1 && timeDiff < 7200) {
                                Activity activity = new Activity();
                                activity.setActiveId(activityJson.getString("id"));
                                activity.setName(activityJson.getString("nameOne"));
                                activity.setCourseId(course.getCourseId());
                                activity.setClazzId(course.getClazzId());
                                activity.setStatus(status);
                                activity.setOtherId(otherId);
                                activity.setActive(true);
                                
                                // 检查是否是班级签到
                                String chatId = activityJson.getString("chatId");
                                String groupId = activityJson.getString("groupId");
                                if (chatId != null || groupId != null) {
                                    log.info("这是一个班级签到活动，chatId: {}, groupId: {}", chatId, groupId);
                                    // 可以在Activity中添加一个标识字段来区分班级签到
                                }
                                
                                // 根据otherId设置签到类型
                                setActivityType(activity, activityJson);
                                
                                activities.add(activity);
                                log.info("添加待签到活动: {} - {} ({})", 
                                    course.getCourseName(), activity.getName(), activity.getType().getDescription());
                            } else {
                                log.debug("活动已超过2小时，忽略");
                            }
                        } else {
                            log.debug("活动不是有效的签到活动: otherId={}, status={}, name={}", 
                                otherId, status, activityJson.getString("nameOne"));
                        }
                    }
                    } else {
                        log.debug("课程 {} 没有活动列表", course.getCourseName());
                    }
                } else {
                    log.debug("课程 {} 返回的数据为空", course.getCourseName());
                }
            }
        } catch (Exception e) {
            log.error("获取活动列表异常", e);
        }
        
        return activities;
    }
    
    private void setActivityType(Activity activity, JSONObject activityJson) {
        Integer otherId = activity.getOtherId();
        switch (otherId) {
            case 0:
                // 需要进一步判断是否是拍照签到
                int ifPhoto = activityJson.getIntValue("ifphoto");
                activity.setType(ifPhoto == 1 ? SignType.PHOTO : SignType.NORMAL);
                break;
            case 2:
                activity.setType(SignType.QRCODE);
                break;
            case 3:
                activity.setType(SignType.GESTURE);
                break;
            case 4:
                activity.setType(SignType.LOCATION);
                break;
            case 5:
                activity.setType(SignType.CODE);
                break;
            default:
                activity.setType(SignType.NORMAL);
        }
    }
    
    public SignResult doSign(Activity activity, Course course) {
        log.info("尝试签到: {} - {} ({})", course.getCourseName(), activity.getName(), activity.getType().getDescription());
        
        try {
            // 先执行预签到
            preSign(activity);
            
            // 根据签到类型执行签到
            switch (activity.getType()) {
                case NORMAL:
                case CODE:
                case GESTURE:
                    return generalSign(activity, course);
                case LOCATION:
                    return locationSign(activity, course);
                case PHOTO:
                    return photoSign(activity, course);
                case QRCODE:
                    return qrcodeSign(activity, course, ""); // 需要二维码内容
                default:
                    return SignResult.builder()
                            .success(false)
                            .message("不支持的签到类型: " + activity.getType().getDescription())
                            .courseName(course.getCourseName())
                            .activityName(activity.getName())
                            .signType(activity.getType())
                            .signTime(new Date())
                            .build();
            }
        } catch (Exception e) {
            log.error("签到异常", e);
            return SignResult.builder()
                    .success(false)
                    .message("签到异常: " + e.getMessage())
                    .courseName(course.getCourseName())
                    .activityName(activity.getName())
                    .signType(activity.getType())
                    .signTime(new Date())
                    .build();
        }
    }
    
    private void preSign(Activity activity) throws IOException {
        String url = String.format("%s?courseId=%s&classId=%s&activePrimaryId=%s&general=1&sys=1&ls=1&appType=15&tid=&uid=%s&ut=s",
                PRESIGN_URL, activity.getCourseId(), activity.getClazzId(), activity.getActiveId(), currentUser.getUid());
        
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Cookie", currentUser.getCookies())
                .build();
        
        try (Response response = client.newCall(request).execute()) {
            log.debug("[预签]已请求");
        }
        
        // 延迟500ms
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    private SignResult generalSign(Activity activity, Course course) {
        try {
            String url = String.format("%s?activeId=%s&uid=%s&clientip=&latitude=-1&longitude=-1&appType=15&fid=%s&objectId=&name=%s",
                    PPT_SIGN_URL, activity.getActiveId(), currentUser.getUid(), "0", 
                    java.net.URLEncoder.encode(currentUser.getName(), "UTF-8"));
            
            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("Cookie", currentUser.getCookies())
                    .build();
            
            try (Response response = client.newCall(request).execute()) {
                String body = response.body().string();
                boolean success = body.equals("success") || body.contains("success");
                
                return SignResult.builder()
                        .success(success)
                        .message(parseSignResult(body))
                        .courseName(course.getCourseName())
                        .activityName(activity.getName())
                        .signType(activity.getType())
                        .signTime(new Date())
                        .build();
            }
        } catch (Exception e) {
            log.error("普通签到异常", e);
            return SignResult.builder()
                    .success(false)
                    .message("签到异常: " + e.getMessage())
                    .courseName(course.getCourseName())
                    .activityName(activity.getName())
                    .signType(activity.getType())
                    .signTime(new Date())
                    .build();
        }
    }
    
    private SignResult locationSign(Activity activity, Course course) {
        if (!config.getLocation().isEnabled()) {
            return SignResult.builder()
                    .success(false)
                    .message("位置签到未启用，请在配置文件中设置位置信息")
                    .courseName(course.getCourseName())
                    .activityName(activity.getName())
                    .signType(SignType.LOCATION)
                    .signTime(new Date())
                    .build();
        }
        
        try {
            String url = String.format("%s?activeId=%s&uid=%s&clientip=&latitude=%s&longitude=%s&appType=15&fid=%s&objectId=&name=%s&address=%s",
                    PPT_SIGN_URL, activity.getActiveId(), currentUser.getUid(),
                    config.getLocation().getLatitude(), config.getLocation().getLongitude(),
                    "0", java.net.URLEncoder.encode(currentUser.getName(), "UTF-8"),
                    java.net.URLEncoder.encode(config.getLocation().getAddress(), "UTF-8"));
            
            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("Cookie", currentUser.getCookies())
                    .build();
            
            try (Response response = client.newCall(request).execute()) {
                String body = response.body().string();
                boolean success = body.equals("success") || body.contains("success");
                
                return SignResult.builder()
                        .success(success)
                        .message(parseSignResult(body))
                        .courseName(course.getCourseName())
                        .activityName(activity.getName())
                        .signType(SignType.LOCATION)
                        .signTime(new Date())
                        .build();
            }
        } catch (Exception e) {
            log.error("位置签到异常", e);
            return SignResult.builder()
                    .success(false)
                    .message("位置签到异常: " + e.getMessage())
                    .courseName(course.getCourseName())
                    .activityName(activity.getName())
                    .signType(SignType.LOCATION)
                    .signTime(new Date())
                    .build();
        }
    }
    
    private SignResult photoSign(Activity activity, Course course) {
        // 拍照签到实现 - 需要上传照片
        return SignResult.builder()
                .success(false)
                .message("拍照签到需要上传照片")
                .courseName(course.getCourseName())
                .activityName(activity.getName())
                .signType(SignType.PHOTO)
                .signTime(new Date())
                .build();
    }
    
    private SignResult qrcodeSign(Activity activity, Course course, String enc) {
        if (enc == null || enc.isEmpty()) {
            return SignResult.builder()
                    .success(false)
                    .message("二维码签到需要提供enc参数")
                    .courseName(course.getCourseName())
                    .activityName(activity.getName())
                    .signType(SignType.QRCODE)
                    .signTime(new Date())
                    .build();
        }
        
        try {
            String url = String.format("%s?enc=%s&activeId=%s&uid=%s&clientip=&latitude=-1&longitude=-1&appType=15&fid=%s&objectId=&name=%s",
                    PPT_SIGN_URL, enc, activity.getActiveId(), currentUser.getUid(),
                    "0", java.net.URLEncoder.encode(currentUser.getName(), "UTF-8"));
            
            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("Cookie", currentUser.getCookies())
                    .build();
            
            try (Response response = client.newCall(request).execute()) {
                String body = response.body().string();
                boolean success = body.equals("success");
                
                return SignResult.builder()
                        .success(success)
                        .message(parseSignResult(body))
                        .courseName(course.getCourseName())
                        .activityName(activity.getName())
                        .signType(SignType.QRCODE)
                        .signTime(new Date())
                        .build();
            }
        } catch (Exception e) {
            log.error("二维码签到异常", e);
            return SignResult.builder()
                    .success(false)
                    .message("二维码签到异常: " + e.getMessage())
                    .courseName(course.getCourseName())
                    .activityName(activity.getName())
                    .signType(SignType.QRCODE)
                    .signTime(new Date())
                    .build();
        }
    }
    
    private String parseSignResult(String result) {
        switch (result) {
            case "success":
                return "签到成功";
            case "fail":
                return "签到失败";
            case "success2":
                return "签到成功";
            default:
                return result;
        }
    }
    
    public boolean isLoggedIn() {
        return currentUser != null && currentUser.isLoginStatus();
    }
    
    // 获取群聊列表
    public List<ChatGroup> getChatGroups() {
        // 学习通的班级签到实际上就是课程签到，不需要单独处理
        // 班级签到和课程签到使用相同的API和逻辑
        log.info("学习通签到说明：课程签到和班级签到使用相同的接口，系统会自动处理所有类型的签到");
        return new ArrayList<>();
    }
    
    // 检查班级签到活动
    public List<Activity> getChatGroupActivities(ChatGroup chatGroup) {
        List<Activity> activities = new ArrayList<>();
        
        try {
            // 使用移动端API获取签到活动
            // 这个API可能需要实时推送或者定期轮询
            log.debug("检查群聊 {} 的签到活动", chatGroup.getChatId());
            
            // 尝试通过课程活动列表API获取班级签到
            // 班级签到可能会出现在课程活动中，但带有特殊标记
            List<Course> courses = getCourses();
            for (Course course : courses) {
                List<Activity> courseActivities = getActivities(course);
                for (Activity activity : courseActivities) {
                    // 检查是否是班级签到（可能通过特定字段区分）
                    if (activity.isActive() && !activity.isSigned()) {
                        activities.add(activity);
                    }
                }
            }
            
        } catch (Exception e) {
            log.error("获取班级签到活动异常", e);
        }
        
        return activities;
    }
    
    // 班级签到预签到
    private void preChatGroupSign(Activity activity, ChatGroup chatGroup) throws IOException {
        String url = String.format("%s?activeId=%s&code=&uid=%s&courseId=null&classId=0&general=0&chatId=%s&appType=0&tid=%s&atype=null&sys=0",
                CHAT_GROUP_PRESIGN_URL, activity.getActiveId(), currentUser.getUid(), 
                chatGroup.getChatId(), chatGroup.getTuid());
        
        Request request = new Request.Builder()
                .url(url)
                .addHeader("Cookie", currentUser.getCookies())
                .build();
        
        try (Response response = client.newCall(request).execute()) {
            log.debug("[班级预签]已请求");
        }
    }
    
    // 执行班级签到
    public SignResult doChatGroupSign(Activity activity, ChatGroup chatGroup) {
        log.info("尝试班级签到: {} - {} ({})", chatGroup.getName(), activity.getName(), activity.getType().getDescription());
        
        try {
            // 先执行预签到
            preChatGroupSign(activity, chatGroup);
            
            // 执行签到
            String url = String.format("%s?activeId=%s&uid=%s&clientip=&latitude=-1&longitude=-1&appType=0&fid=0&objectId=&name=%s",
                    CHAT_GROUP_SIGN_URL, activity.getActiveId(), currentUser.getUid(), 
                    java.net.URLEncoder.encode(currentUser.getName(), "UTF-8"));
            
            if (activity.getType() == SignType.LOCATION && config.getLocation().isEnabled()) {
                url = String.format("%s?activeId=%s&uid=%s&clientip=&latitude=%s&longitude=%s&appType=0&fid=0&objectId=&name=%s&address=%s",
                        CHAT_GROUP_SIGN_URL, activity.getActiveId(), currentUser.getUid(),
                        config.getLocation().getLatitude(), config.getLocation().getLongitude(),
                        java.net.URLEncoder.encode(currentUser.getName(), "UTF-8"),
                        java.net.URLEncoder.encode(config.getLocation().getAddress(), "UTF-8"));
            }
            
            Request request = new Request.Builder()
                    .url(url)
                    .addHeader("Cookie", currentUser.getCookies())
                    .build();
            
            try (Response response = client.newCall(request).execute()) {
                String body = response.body().string();
                boolean success = body.equals("success") || body.contains("success");
                
                return SignResult.builder()
                        .success(success)
                        .message(parseSignResult(body))
                        .courseName("班级群聊")
                        .activityName(activity.getName())
                        .signType(activity.getType())
                        .signTime(new Date())
                        .build();
            }
        } catch (Exception e) {
            log.error("班级签到异常", e);
            return SignResult.builder()
                    .success(false)
                    .message("班级签到异常: " + e.getMessage())
                    .courseName("班级群聊")
                    .activityName(activity.getName())
                    .signType(activity.getType())
                    .signTime(new Date())
                    .build();
        }
    }
}